use std::{str::FromStr, sync::Arc};

use futures_util::future::{ok, ready, Ready};
use http::{HeaderMap, Uri};
use tokio::{
    io::{self, AsyncReadExt},
    net::TcpStream,
    sync::Mutex,
};

use super::{handler::FromRequest, Method, Protocol};

#[derive(Debug)]
pub struct Body {
    len: usize,
    reader: Arc<Mutex<TcpStream>>,
    buf: Vec<u8>,
}

impl Body {
    pub fn new(len: usize, reader: Arc<Mutex<TcpStream>>, buf: Vec<u8>) -> Self {
        Self { len, reader, buf }
    }

    pub fn len(&self) -> usize {
        self.len
    }

    pub fn is_empty(&self) -> bool {
        self.len == 0
    }

    pub async fn array(self) -> io::Result<Vec<u8>> {
        let mut result = Vec::with_capacity(self.len);
        result.extend(self.buf);
        let mut len = self.len - result.len();
        if len == 0 {
            return Ok(result);
        }
        const BUF_LEN: usize = 512;
        let mut buf = [0; BUF_LEN];
        let mut reader_guard = self.reader.lock().await;
        loop {
            let amt = reader_guard
                .read_exact(&mut buf[..len.min(BUF_LEN)])
                .await?;
            result.extend_from_slice(&buf[..amt]);
            if len <= buf.len() {
                break;
            }
            len -= amt;
        }
        Ok(result)
    }

    pub async fn text(self) -> io::Result<String> {
        let result = self.array().await?;
        Ok(String::from_utf8_lossy(&result).to_string())
    }
}

impl FromRequest for Body {
    type Future = Ready<Result<Self, anyhow::Error>>;

    fn from_request(_: &Request, body: &mut Option<Body>) -> Self::Future {
        ready(match body.take() {
            Some(body) => Ok(body),
            None => Err(anyhow::Error::msg("Body None!")),
        })
    }
}

#[derive(Debug, Clone)]
pub struct Request {
    inner: Arc<RequestInner>,
}

#[derive(Debug)]
struct RequestInner {
    method: Method,
    protocol: Protocol,
    uri: Uri,
    headers: HeaderMap,
    server_port: u16,
}

impl Request {
    pub fn new(
        method: Method,
        protocol: Protocol,
        uri: &str,
        headers: HeaderMap,
        server_port: u16,
    ) -> Self {
        Self {
            inner: Arc::new(RequestInner {
                method,
                protocol,
                uri: Uri::from_str(uri).expect("Uri prase error"),
                headers,
                server_port,
            }),
        }
    }

    pub fn protocol(&self) -> Protocol {
        self.inner.protocol
    }

    pub fn method(&self) -> Method {
        self.inner.method
    }

    pub fn uri(&self) -> &Uri {
        &self.inner.uri
    }

    // pub fn take_body(&mut self) -> Option<Body<'a>> {
    //     self.body.take()
    // }

    // pub fn into_body(self) -> Body<'a> {
    //     self.body.unwrap()
    // }

    pub fn headers(&self) -> &HeaderMap {
        &self.inner.headers
    }

    pub fn server_port(&self) -> u16 {
        self.inner.server_port
    }
}

impl FromRequest for Request {
    type Future = Ready<Result<Self, anyhow::Error>>;

    fn from_request(req: &Request, _: &mut Option<Body>) -> Self::Future {
        ok(req.clone())
    }
}

pub struct ServiceRequest {
    pub req: Request,
    pub body: Option<Body>,
}
